package org.nepu.su.controller;

import cn.afterturn.easypoi.word.WordExportUtil;
import cn.afterturn.easypoi.word.entity.MyXWPFDocument;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Validator;
import cn.hutool.json.JSONUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.lboot.core.auth.anno.AuthLogin;
import org.lboot.core.domain.ResponseDTO;
import org.lboot.jpa.utils.JpaDataUtil;
import org.lboot.ufs.entity.UfsFile;
import org.lboot.ufs.service.UfsCtl;
import org.nepu.sc.dict.SafeRateDict;
import org.nepu.sc.dict.SafeRateDictService;
import org.nepu.sc.domain.RiskResult;
import org.nepu.sc.ignore.SafeIgnoreUnit;
import org.nepu.sc.ignore.SafeIgnoreUnitService;
import org.nepu.sc.mx.SafeMx;
import org.nepu.sc.mx.SafeMxService;
import org.nepu.sc.task.SafeTask;
import org.nepu.sc.task.SafeTaskService;
import org.nepu.sc.template.SafeExport;
import org.nepu.sc.template.SafeExportService;
import org.nepu.sc.template.params.SafeExportQueryParams;
import org.nepu.sc.unit.SafeUnit;
import org.nepu.sc.unit.SafeUnitService;
import org.nepu.scr.template.ExportTemplate;
import org.nepu.scr.template.params.ExportTemplateCreateParams;
import org.nepu.scr.template.params.ExportTemplateQueryParams;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("safe")
@AllArgsConstructor
@Api(tags = "安全评价导出管理")
public class SafeExportController {

    SafeUnitService unitService;
    SafeIgnoreUnitService ignoreUnitService;

    SafeExportService safeExportService;
    SafeTaskService taskService;
    SafeRateDictService dictService;
    SafeMxService mxService;

    UfsCtl ufsCtl;

    SafeUnitController stCtl;

    @AuthLogin
    @PostMapping("templates")
    @ApiOperation(value = "导出模板新增")
    public ResponseDTO<Object> exportTemplateAdd(ExportTemplateCreateParams params){
        MultipartFile file = params.getFile();
        UfsFile ufsFile = ufsCtl.uploadFile(file, "导出模板/");
        SafeExport template = new SafeExport();
        template.setTemplateFileId(ufsFile.getId());
        template.setTemplateDesc(params.getTemplateDesc());
        template.setTemplateVersion(params.getTemplateVersion());
        return ResponseDTO.succData(
                safeExportService.saveOne(template)
        );
    }

    @AuthLogin
    @GetMapping("templates")
    @ApiOperation(value = "导出模板列表")
    public ResponseDTO<Object> exportTemplateList(SafeExportQueryParams params){
        Pageable pageable = JpaDataUtil.buildPageable(params);
        Specification<SafeExport> spec = (root, query, cb) -> {
            return cb.like(root.get("templateDesc"),"%"+params.getSearchKey()+"%");
        };
        if (Validator.isEmpty(params.getSearchKey())){
            return ResponseDTO.succData(
                    safeExportService.getAll(pageable)
            );
        }else {
            return ResponseDTO.succData(
                    safeExportService.getAll(pageable,spec)
            );
        }
    }

    @AuthLogin
    @DeleteMapping("templates/{id}")
    @ApiOperation(value = "导出模板删除")
    public ResponseDTO<Object> exportTemplateDelete(@PathVariable("id") Long id){
        SafeExport template = safeExportService.getOneUnwrap(id);
        ufsCtl.deleteFile(template.getTemplateFileId());
        safeExportService.deleteOne(id);
        return ResponseDTO.succMsg("删除成功");
    }


    @AuthLogin
    @GetMapping("export")
    @ApiOperation(value = "指标评价结果导出")
    @SneakyThrows
    public void wordExport(@RequestParam("taskId") String taskId, @RequestParam(value = "templateFileId",required = false) String templateFileId
            , HttpServletResponse response){
        InputStream stream = ufsCtl.getFileStream(templateFileId);

        List<SafeUnit> units = unitService.getByTaskId(taskId);
        List<SafeIgnoreUnit> ignoreUnits = ignoreUnitService.getByTaskId(taskId);
        String taskName = taskService.getOneUnwrap(taskId).getTaskName();
        XWPFDocument document = new MyXWPFDocument(stream);
        List<SafeRateDict> dicts = dictService.getAll();
        //生成文本内容Map
        Map<String, Object> contentMap = buildContentMap(taskId,units,dicts,ignoreUnits);

        //替换文本内容
        WordExportUtil.exportWord07(document, contentMap);

        //返回流
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream;charset=UTF-8");
        /**
         * 修改导出文件名称
         */
        String encodedFileName = URLEncoder.encode(taskName + "安全评价报告.docx", StandardCharsets.UTF_8.toString());
        response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"; filename*=utf-8''" + encodedFileName);
//        response.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName+".docx");
        OutputStream outputStream = response.getOutputStream();
        document.write(outputStream);
        outputStream.flush();

        outputStream.close();
    }

    @SneakyThrows
    public Map<String,Object> buildContentMap(String taskId,List<SafeUnit> units,List<SafeRateDict> dicts,List<SafeIgnoreUnit> ignoreUnits){

        Map<String, Object> contentMap = new HashMap<>();

        List<SafeMx> mxs = mxService.getAll();
        Map<String, String> dictMap = new HashMap<>();
        for (SafeRateDict dict:dicts){
            dictMap.put(dict.getRateId(), dict.getRateName());
        }

        List<String> exportList = exportRate();

        for (String item : exportList) {
            RiskResult r = stCtl.buildUnitResult(item,units,dictMap,mxs,ignoreUnits);
            String formattedNumber = String.format("%.3f", r.getRiskScore() * 1000);
            contentMap.put(item+"风险等级", r.getRiskLevel());
            contentMap.put(item+"风险得分", formattedNumber);
        }

        for (SafeUnit unit:units){
            //处理data,可能是合格/不合格/TF数组
            if(JSONUtil.isTypeJSONArray(unit.getRateParams().getData())){
                List<Boolean> dataList = JSONUtil.toList(unit.getRateParams().getData(),Boolean.class);
                Boolean flag = true;
                for (Boolean d:dataList){
                    if(!d){
                        flag = false;
                        break;
                    }
                }
                if(flag){
                    contentMap.put(unit.getRateId()+"结果","合格");
                }else {
                    contentMap.put(unit.getRateId()+"结果","不合格");
                }
            }else {
                contentMap.put(unit.getRateId()+"结果",unit.getRateParams().getData());
            }
            //处理dataName，可能是字符/字符数组
            if(parentIds().contains(unit.getParentId()) || rateIds().contains(unit.getRateId())){
                if (JSONUtil.isTypeJSONArray(unit.getRateParams().getDataName())){
                    List<String> dataList = JSONUtil.toList(unit.getRateParams().getDataName(),String.class);
                    Boolean flag = true;
                    for (int i = 0;i<dataList.size();i++){
                        String d = dataList.get(i);
                        if(d.equals("无")){
                            flag = false;
                        }
                        contentMap.put(unit.getRateId()+(i+1),d);
                    }
                    if(flag){
                        contentMap.put(unit.getRateId()+"结果","合格");
                    }else {
                        contentMap.put(unit.getRateId()+"结果","不合格");
                    }
                }else {
                    contentMap.put(unit.getRateId(),unit.getRateParams().getDataName());
                }
            }
            contentMap.put(unit.getRateId()+"得分",unit.getRateParams().getImportant());
            contentMap.put(unit.getRateId()+"备注",unit.getRateParams().getRemark());
        }
        return contentMap;
    }

    public static List<String> exportRate(){
        List<String> exportList = Arrays.asList(
                "a", "a1", "a2", "a3", "a4", "a5",
                "b", "b1", "b2", "b3", "b4", "b5",
                "c", "c1", "c2", "c3", "c4", "c5",
                "d", "d1", "d2", "d3", "d4", "d5",
                "e", "e1", "e2", "e3", "e4", "e5"
        );
        return exportList;
    }

    public static List<String> parentIds(){
        List<String> parentList = Arrays.asList(
                "a51","a52","a53","a54","a55",
                "b42","b43","b44","b45","b46","b47","b48","b49","b4a","b4b",
                "c1","e32","e33","e34","e35","e36"
        );
        return parentList;
    }

    public static List<String> rateIds(){
        List<String> rateList = Arrays.asList(
                "a4116","a411a","a411m","a411n","a411u",
                "a4122","a4123","a413n","a413G","a413L",
                "a4415","a4517",
                "a563","a564","a565","a566","a567","a568",
                "b2316","b231a","b231m","b231n","b231u",
                "b2322","b2323",
                "b235e","b235f","b2375","b23a7","b23fn","b23fL","b23gf",
                "b4c3","b4c4","b4c5","b4c6","b4c7","b4c8",
                "c216","c21a","c21m","c21n","c21u",
                "c22n","c22G","c22L",
                "d1316","d131a","d131m","d131n","d131u",
                "d1322","d1323",
                "d134e","d134f","d1397","d13en","d13eG","d13eL","d13ff",
                "d341","d342","d343","d344",
                "e13115","e13218","e1322i","e132311","e132312","e13232f",
                "e13242","e13252","e13422","e13423",
                "e373","e374","e375","e376","e377","e378"
        );
        return rateList;
    }

}
